#pragma once
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include<string>
#include "Logger.hpp"
#include "InetAddr.hpp"

const static int defaultfd = -1;
const static int backlog = 16;

enum
{
    SOCK_CREATE_ERRO,
    SOCK_BIND_ERRO,
    SOCK_LISTEN_ERRO
};

// 模板继承类模式
class Socket
{
public:
    virtual ~Socket() {}
    virtual void CreateSocket() = 0;
    virtual void BindSocket(uint16_t port) = 0;
    virtual void ListenSocket() = 0;
    virtual std::shared_ptr<Socket> Accept(InetAddr*clientaddr) = 0;
    virtual void Close() = 0;
    virtual ssize_t Recv(std::string*out) = 0;
    virtual ssize_t Send(std::string&in)=0;
public:
    void BuildSocket(uint16_t port)
    {
        CreateSocket();
        BindSocket(port);
        ListenSocket();
    }
};

class TcpSocket : public Socket
{
public:
    TcpSocket() : _sockfd(defaultfd)
    {
    }
    TcpSocket(int sockfd) : _sockfd(sockfd)
    {
    }
    void CreateSocket() override
    {
        _sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_sockfd < 0)
        {
            LOG(LogLevel::FATAL) << "socket创建失败";
            exit(SOCK_CREATE_ERRO);
        }
        LOG(LogLevel::INFO) << "socket创建成功";
    }
    void BindSocket(uint16_t port) override
    {
        // 绑定本地网络地址
        InetAddr addr(port);
        if (bind(_sockfd, addr.Addr(), addr.Length()) != 0)
        {
            LOG(LogLevel::FATAL) << "bind Socket失败";
            exit(SOCK_BIND_ERRO);
        }
        LOG(LogLevel::INFO) << "bind socket成功";
    }
    void ListenSocket() override
    {
        if (listen(_sockfd, backlog) != 0)
        {
            LOG(LogLevel::FATAL) << "listen socket失败";
            exit(SOCK_LISTEN_ERRO);
        }
        LOG(LogLevel::INFO) << "listen socket成功";
    }
    std::shared_ptr<Socket> Accept(InetAddr*clientaddr) override
    {
        // 获取对方服务器网络地址
        struct sockaddr_in addr;
        socklen_t len = sizeof(addr);
        int fd = accept(_sockfd, (struct sockaddr *)&addr, &len);
        if (fd < 0)
        {
            LOG(LogLevel::WARNING) << "获取新连接失败";
            return nullptr;
        }
        clientaddr->Init(addr);
        return std::make_shared<TcpSocket>(fd);
    }
    void Close() override
    {
        close(_sockfd);
    }
    ssize_t Recv(std::string*out) override
    {
        char buffer[1024];
        buffer[0] = 0;
        ssize_t n = recv(_sockfd, buffer, sizeof(buffer) - 1, 0);
        if (n > 0)
        {
            buffer[n]=0;
            *out+=buffer;
        }
        return n;
    }
    ssize_t Send(std::string&in) override
    {
        ssize_t n=send(_sockfd,in.c_str(),in.size(),0);
        return n;
    }
    ~TcpSocket() {}

private:
    int _sockfd;
};